package cn.jbolt.core.enjoy.directive;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import cn.jbolt.core.base.config.JBoltConfig;
import cn.jbolt.core.consts.JBoltConst;
import cn.jbolt.core.kit.JBoltHttpSchemeKit;
import com.jfinal.template.Directive;
import com.jfinal.template.Env;
import com.jfinal.template.expr.ast.Expr;
import com.jfinal.template.expr.ast.ExprList;
import com.jfinal.template.io.Writer;
import com.jfinal.template.stat.ParseException;
import com.jfinal.template.stat.Scope;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * 网络图片转base64
 *
 * @ClassName: ImageUrlToBase64Directive
 * @author: JFinal学院-小木 QQ：909854136
 * @date: 2021年2月15日17:43:51
 */
public class ImageUrlToBase64Directive extends Directive {
	private Expr urlExpr;
	/**
	 * 是否为系统内数据 系统内地址需要自己增加前缀domain
	 */
	private Expr innerExpr;
	private int paraNum;

	@Override
	public void setExprList(ExprList exprList) {
		this.paraNum = exprList.length();
		if (paraNum == 0) {
			throw new ParseException(
					"Wrong number parameter of #imgurlToBase64 directive, one parameters allowed at most", location);
		} else if (paraNum == 1) {
			this.urlExpr = exprList.getExpr(0);
		} else if (paraNum == 2) {
			this.urlExpr = exprList.getExpr(0);
			this.innerExpr = exprList.getExpr(1);
		}
	}

	@Override
	public void exec(Env env, Scope scope, Writer writer) {
		if (paraNum == 0) {
			outputNothing(env, writer);
		} else {
			outputBase64(env, scope, writer);
		}
	}

	private void outputBase64(Env env, Scope scope, Writer writer) {
		if (this.urlExpr == null) {
			outputNothing(env, writer);
			return;
		}

		Object urlObj = this.urlExpr.eval(scope);
		if (urlObj == null) {
			outputNothing(env, writer);
			return;
		}

		String url = urlObj.toString();
		if (StrUtil.isBlank(url)) {
			outputNothing(env, writer);
			return;
		}
		boolean isInner = false;
		if (this.innerExpr != null) {
			Object innerObj = this.innerExpr.eval(scope);
			if (innerObj != null) {
				String isInnerStr = innerObj.toString();
				if (StrUtil.isNotBlank(isInnerStr)) {
					isInner = Boolean.parseBoolean(isInnerStr);
				}
			}
		}
		// 如果是内部资源 并且还真的没有http开头 就需要拼接domain
		if (isInner && url.startsWith("http://") == false && url.startsWith("https://") == false) {
			String domain = JBoltConfig.WORD_IMG_INNER_DOMAIN;
			if (StrUtil.isBlank(domain)) {
				domain = JBoltConfig.DOMAIN;
			}
			if (StrUtil.isBlank(domain)) {
				outputNothing(env, writer);
				return;
			}
			domain = JBoltHttpSchemeKit.getFull() + domain;
			if (domain.endsWith("/")) {
				if (url.startsWith("/")) {
					url = domain + url.substring(1);
				} else {
					url = domain + url;
				}
			} else {
				if (url.startsWith("/")) {
					url = domain + url;
				} else {
					url = domain + "/" + url;
				}
			}

		}
		String base64 = image2Base64(url);
		if (base64 == null) {
			outputNothing(env, writer);
			return;
		}

		try {
			writer.write(base64);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 输出空字符
	 *
	 * @param env
	 * @param writer
	 */
	private void outputNothing(Env env, Writer writer) {
		try {
			writer.write(JBoltConst.IMG_NOTHING_BASE64_FILE);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 远程读取image转换为Base64字符串
	 *
	 * @param imgUrl
	 * @return
	 */
	public static String image2Base64(String imgUrl) {
		if (imgUrl.startsWith("http://") == false && imgUrl.startsWith("https://") == false) {
			return null;
		}
		URL url = null;
		InputStream is = null;
		ByteArrayOutputStream outStream = null;
		HttpURLConnection httpUrl = null;
		try {
			url = new URL(imgUrl);
			httpUrl = (HttpURLConnection) url.openConnection();
			httpUrl.connect();
			httpUrl.getInputStream();
			is = httpUrl.getInputStream();

			outStream = new ByteArrayOutputStream();
			// 创建一个Buffer字符串
			byte[] buffer = new byte[1024];
			// 每次读取的字符串长度，如果为-1，代表全部读取完毕
			int len = 0;
			// 使用一个输入流从buffer里把数据读取出来
			while ((len = is.read(buffer)) != -1) {
				// 用输出流往buffer里写入数据，中间参数代表从哪个位置开始读，len代表读取的长度
				outStream.write(buffer, 0, len);
			}
			// 对字节数组Base64编码
			return Base64.encode(outStream.toByteArray());
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (outStream != null) {
				try {
					outStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (httpUrl != null) {
				httpUrl.disconnect();
			}
		}
	}

}
